package com.qianya.weishi_server.common;

import com.alibaba.druid.util.StringUtils;
import com.qianya.weishi_server.common.exception.GenericException;
import com.qianya.weishi_server.common.result.CommonResult;
import com.qianya.weishi_server.common.result.ErrorCode;
import com.qianya.weishi_server.common.result.GenericErrorCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.validation.BindException;
import org.springframework.validation.FieldError;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.HttpStatusCodeException;

import javax.validation.ConstraintViolationException;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 全局错误处理
 * <p>
 * 处理我们定义的ApiException和Spring的所有Exception
 * <p>
 * 封装成json的形式进行response
 */
@ControllerAdvice
@ResponseBody
@Slf4j
public class GenericExceptionHandler {

    //默认异常返回
    @ExceptionHandler({Exception.class})
    public CommonResult handleExceptionBase(Exception e) {
        return getError(e, GenericErrorCode.ERROR, e.getMessage());
    }

    //1、后端的实体类与前端的传入参数数据类型不一致
    //2、我们使用@RequestBody注解，但是我们请求方式是get请求，可以修改请求方式，或者使用get请求的话用@RequestParam和@PathVariable
    //3、跨域、未序列化
    @ExceptionHandler({HttpMessageNotReadableException.class})
    public CommonResult handleHttpMessageNotReadableException(Exception e) {
        return getError(e, GenericErrorCode.PARAM_TYPE_ERROR, e.getMessage());
    }


    @ExceptionHandler({ConstraintViolationException.class})
    public CommonResult handleConstraintViolationException(ConstraintViolationException e) {
        return getError(e, GenericErrorCode.PARAM_ERROR, e.getMessage());
    }

    //请求方式不支持
    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
    public CommonResult handleHttpRequestMethodNotSupportedException(Exception e) {
        return getError(e, GenericErrorCode.HTTP_REQUEST_ERROR, e.getMessage());
    }

//    @ExceptionHandler({MissingServletRequestParameterException.class})
//    public CommonResult missingServletRequestParameterHandler(MissingServletRequestParameterException e) {
//        e.printStackTrace();
//        return CommonResult.error(e.getParameterName() + ":值不能为空");
//    }
//
//    @ExceptionHandler({DuplicateKeyException.class})
//    public CommonResult duplicateKeyExceptionHandler(DuplicateKeyException e) {
//        String message = e.getCause().getMessage();
//        String s = message.split("'")[1].split("'")[0];
//        e.printStackTrace();
//        return CommonResult.error(s + ":值重复");
//    }

    //MissingServletRequestParameterException：@RequestParam参数为null时抛出的异常
    @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class, MissingServletRequestParameterException.class})
    public CommonResult handleValidException(Exception e) {
        return getError(e, GenericErrorCode.PARAM_ERROR, e.getMessage());
    }


    //自定义异常
    @ExceptionHandler({GenericException.class})
    public CommonResult handleGenericException(GenericException e) {
        return getError(e, e.getErrorCode(), e.getMessage());
    }


    private CommonResult getError(Exception e, ErrorCode errorCode, String detailMsg) {
        log.error("", e);
        CommonResult error = new CommonResult<>(errorCode.getCode(), errorCode.getMessage(), detailMsg);
        try {
            /*if (request instanceof ServletWebRequest) {
                ServletWebRequest servletWebRequest = (ServletWebRequest) request;
                error.setPath(servletWebRequest.getRequest().getServletPath());
            }*/
            if (e instanceof MethodArgumentNotValidException) {
                MethodArgumentNotValidException ex = (MethodArgumentNotValidException) e;
                List<FieldError> fieldErrors = ex.getBindingResult().getFieldErrors();
                String message = fieldErrors.stream().map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.joining(";"));
                error.setCode(GenericErrorCode.PARAM_ERROR.getCode());
                error.setMsg(message);
            }
            if (e instanceof HttpStatusCodeException) {
                String message = ((HttpStatusCodeException) e).getResponseBodyAsString();
                log.error("remote error:{}", message);
            }
            if (e instanceof GenericException) {
                String defaultMsg = errorCode.getClass().getSimpleName() + "." + errorCode;
                String msg = e.getMessage();
                if (!StringUtils.equals(defaultMsg, msg)) {
                    error.setCode(((GenericException) e).getErrorCode().getCode());
                    error.setMsg(msg);
                }
            }
        } catch (Exception e2) {
            log.error("异常处理，设置异常返回异常", e2);
        }
        return error;
    }
}
